/*
Implement setenv() and unsetenv() using getenv(), putenv(), and, where necessary,
code that directly modifies environ. Your version of unsetenv() should check to see
whether there are multiple definitions of an environment variable, and remove
them all (which is what the glibc version of unsetenv() does).
 */

/*
Not complete but we know all what to do :)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern char **environ;

static size_t
get_environment_size(void)
{
  size_t env_size = 0;
  char **envp = environ;
  while (*envp++) ++env_size;

  return env_size;
}

int
setenv(const char *name, const char *value, int overwrite)
{
  static char **last_environment;
  size_t environment_cache = strlen(name) + strlen(value) + 2;
  char *buffer = malloc(environment_cache);
  snprintf(buffer, environment_cache, "%s=%s", name, value);
  if (overwrite)
    {
      putenv((char*)buffer);
    }
  else
    {
      char *name_env;
      if ((name_env = getenv(name)) != NULL)
        {
          size_t max_size = get_environment_size();
          if (last_environment != NULL)
            last_environment = realloc(last_environment, max_size + 2);
          else
            {
              last_environment = realloc(last_environment, max_size + 2);
              memcpy(last_environment, environ, max_size * sizeof(void *));
            }
          last_environment[max_size] = strdup(buffer);
          last_environment[max_size + 1] = NULL;
          environ = last_environment;
        }
      else
        {
          putenv((char*)buffer);
        }
    }

  printf("%p and %p\n", buffer, environ[0]);
  return 0;
}

int
unsetenv(const char *name)
{
  return putenv((char*)name);
}

static void
printenv(void)
{
  for(char **ep = environ; ep && *ep; ++ep)
    printf("%s ", *ep);
  printf("\n");
}

/*
putenv require heap memory or static storage it doesn't copy
https://wiki.sei.cmu.edu/confluence/display/c/POS34-C.+Do+not+call+putenv()+with+a+pointer+to+an+automatic+variable+as+the+argument
it doesn't release memory too
 */

int
main(void)
{
  printf("%p\n", environ);
  clearenv();
  printenv();
  setenv("name", "daniel", 0);
  printenv();
  setenv("name", "alex", 1);
  printenv();
  setenv("name", "daniel", 0);
  printenv();
  clearenv();

return EXIT_SUCCESS;
}
